สร้าง Formula สำหรับติดตามพัสดุของไปรษณีย์ไทยใน Google Sheets กันเถอะ
Table of Contents
เมื่อไปรษณีย์ไทยเปิด API ให้เราเข้าไปดึงข้อมูลพัสดุได้แล้ว วันนี้เรามาลองเขียน Fomular สำหรับดึงเอาสถานะของพัสดุไปรษณีย์ไทยมาอยู่ใน Google Sheets กันดีกว่า
=ThailandPostTrack("หมายเลข EMS", "recent")
บอกไว้ก่อน #
ก่อนจะเข้าเนื้อหาผมอยากให้ทุกคนศึกษาพื้นฐานของสิ่งเหล่านี้ก่อนนะครับ
- Google Apps Script และ Clasp หลายคนอาจจะรู้จัก Apps Script แต่อาจจะไม่รู้จัก Clasp ลองเข้าไปอ่านที่นี่ก่อนนะครับ มาเขียน Google Apps Script บน local กันเถอะ (ใช้ modern javascript ได้ด้วยนะ)
ทำความรู้จัก Thailand Post API #
เรียกได้ว่าสิ้นสุดการรอคอยกับ API ที่นักพัฒนาชาวไทยตั้งหน้าตั้งตารอมากที่สุด ตอนนี้ไปรษณีย์ไทยก็เปิดให้ทุกคนเข้าไปใช้งานได้แล้วที่นี่ครับ https://track.thailandpost.co.th

เริ่มจากสมัครสมาชิก #
เข้าไปที่ https://track.thailandpost.co.th/register แล้วเลือกประเภทของการใช้งานของคุณเลยครับ สำหรับผมคือ “ลูกค้าทั่วไป” เพราะเราเอามาใช้ส่วนตัวทดลองอะไรเล็กๆน้อยๆเท่านั้นเอง ส่วนนี้ผมจะขอข้ามนะครับเพราะกรอกฟอร์มตามปกติไม่มีอะไรซับซ้อนทุกคนน่าจะเข้าใจกันอยู่แล้ว

มีอะไรให้ใช้บ้าง #
หลังจากสมัครสมาชิกเรียบร้อยแล้วให้ทำการ “เข้าสู่ระบบ” แล้วคลิกที่เมนูด้านซ้ายที่เขียนว่า “สำหรับนักพัฒนา”

ภายในนี้จะมีหัวข้อหลักๆ 2 หัวข้อดังนี้ครับ
- API เป็นส่วนที่เราจะใช้ครับ เพราะเราจะใช้ Google Apps Script ยิง request มาที่นี่เพื่อขอข้อมูลสถานะพัสดุ
- Webhook อันนี้ผมไม่ได้ใช้แต่จะขออธิบายให้เข้าใจง่ายๆว่ามันเป็นการที่เราบอกไปรษณีย์ว่าถ้ามีข้อมูลเปลี่ยนแปลงให้ทำการยิงไปที่ url ที่เรากำหนดไว้ด้วยนะ ตัวนี้จะมีประโยชน์ตรงที่เราไม่ต้องคอยยิงไปถามเรื่อยๆเพื่อตรวจสอบว่ามีอะไร update ไหม ไปรษณีย์จะเป็นคนบอกเราเองเวลามีอะไร update เหมาะกับการเอาไปทำ chatbot ที่มัน Notify ผู้ใช้งานว่าของไปถึงไหนแล้ว
ก่อนใช้ API ต้องสร้าง Token #
กดที่ “Create Token” หลังจากนั้นกด “สร้าง” อีกทีครับเพียงเท่านี้เราก็จะใช้ Token ชุดแรกเอาไว้ไปใช้งาน API แล้ว สำหรับใครที่สร้างไปแล้วไม่จำเป็นต้องสร้างใหม่อีกนะครับ เพียงแค่กด “Create Token” เว็บจะแสดง Current Token ให้ด้วย

ใครได้แล้วก็อย่าลืม copy ตัว token เอาไว้นะครับ ของผมก็จะเป็นตัวนี้
ZfPSL:MzEfEmTdMaGTSoZPJLDYE-KEIpBoWQU?GnQUC9FzI7PxPuUOTFY-D6Z4AOCLUNGTOOEPqY6NBGBLMYlJxDHUGET@HOUT
ต่อไปก็คลิกที่ “เอกสารสำหรับการพัฒนา” หรือเข้าไปที่ url https://track.thailandpost.co.th/developerGuide ก็ได้เช่นกันครับ
API มีอะไรบ้าง #
ใน API Documentation จะมีอธิบายทุกอย่างเกี่ยวกับ API เอาไว้นะครับตั้งแต่ความหมายของ Status Item
การเรียกใช้แบบต่างๆ ทั้ง SOAP และ REST ไปจนถึงการใช้งาน Web hook นะครับ แต่เพื่อไม่ให้บทความนี้ยาวเกินไปเราจะดูเฉพาะส่วนที่เราจะใช้คือ API REST นะครับ

ภายใน REST ก็จะประกอบด้วย endpoint หลักๆ 3 ตัวดังนี้ครับ
- GetToken ใช้สำหรับขอ
AccessToken
อีกชุดเพื่อใช้ในGetItems
และReqiestItems
แต่ว่าการขอต้องใช้ Token ที่เรากดมาเมื่อกี้นี้ไปขอด้วยนะครับ ตัวนี้มีอายุ 1 เดือน หมดอายุก็ต้องขอใหม่ - GetItems ใช้ GET ข้อมูลพัสดุแต่ครั้งละไม่เกิน 100 ชิ้นครับ API จะ return กลับมาให้ใน HTTPResponse เลย ซึ่งเราจะใช้ตัวนี้
- RequestItems ใช้ GET ข้อมูลพัสดุเหมือนกันแต่สำหรับจำนวนมากๆ 100 ชิ้นขึ้นไปครับ ตัวนี้ API จะส่ง link ของไฟล์ข้อมูลไปให้ใน Email แทนนะครับ
สรุปเรื่อง Token อีกรอบเผื่องง #
- ให้ไป Create Token ในหน้าเว็บแล้วจะได้ Token มา 1 ชุด คือ
Static Token
- นำ
Static Token
ไปขอ Token ใหม่ที่ endpoint GetToken จะได้AccessToken
ใหม่อีกชุดมีอายุ 1 เดือน - นำ
AccessToken
ไปใช้ขอ GetItems
สร้าง GAS Project #
เตรียม Apps Script Starter #
เริ่มจากการ clone Apps Script Starter แล้วก็ติดตั้ง dependency package ก่อนเลยครับ
git clone https://github.com/labnol/apps-script-starter thailand-post-tracker
cd thailand-post-tracker
npm install
สร้าง Project บน Apps Script บ้าง โดยเลือก type เป็น sheets
นะครับ
npx clasp create --type sheets --title "thailand-post-tracker" --rootDir ./dist
เตรียม sheets ให้สำหรับทำงาน #
เปิด sheets ชื่อ “thailand-post-tracker” ใน Google Drive ขึ้นมา แล้วสร้าง sheet ใหม่ขึ้นมาชื่อ “Token” เผื่อเอาไว้เก็บ Token ที่เราจะใช้กันนะครับ

เพื่อความสะดวกในการอ้างอิงถึง cell ผมจะทำการตั้งชื่อให้มันซะเลย โดยคลิกขวาที่ cell แล้วเลือก Define named range

ผมตั้งไว้ 2 cells คือ StaticToken
และ AccessToken
ตามภาพนะครับเป็น B1
กับ B2

สร้างส่วนติดต่อกับ API ใน Google Apps Script #
ผมจะเขียนส่วนของ service แยกออกมาครับ เริ่มจาก getToken กันก่อนเลย
src/service/index.js
const url = 'https://trackapi.thailandpost.co.th/post/api/v1';
export default {
getToken(staticToken) {
// เตรียม option ในการส่งตาม API Documentation
const options = {
method: 'POST',
contentType: 'application/json',
//กำหนด headers ตามที่ document บอกให้ครบด้วยนะครับ
headers: {
Authorization: `Token ${staticToken}`,
'Content-Type': 'application/json'
},
validateHttpsCertificates: false //เนื่องจาก https ของ API ยังไม่ certify เราจะ skip มันซะ
};
//fecth ไปยัง API ของ Thailand Post
const data = UrlFetchApp.fetch(`${url}/authenticate/token`, options);
//ได้ token ไปใช้ต่อ
const { token } = JSON.parse(data);
return token;
}
};
สร้างเมนูสำหรับเพื่อความสะดวกในการขอ AccessToken #
ที่ src/index.js
ผมสร้างเมนูไว้ใน onOpen()
ครับเพราะมันจะถูก call ทันทีตอนที่เปิด sheet ส่วน getNewAccessToken()
ตรงนี้ผมจะเรียก cell จาก Named range ที่ตั้งชื่อเอาไว้นะครับ ซึ่งผมจะใช้ staticToken
ที่ได้มาจาก sheet ส่งไปขอ ThailandPost.getToken()
แล้วหลังจากนั้นค่อยเอาไปเขียนที่ cell ของ AccessToken
src/index.js
import ThailandPost from './service';
const onOpen = () => {
const ui = SpreadsheetApp.getUi();
//สร้าง Menu ชื่อ Thailand Post Tracker บน Sheet
//มี Submenu ชื่อ Renew AccessToken เมื่อคลิกแล้วจะ cell getNewAccessToken()
ui.createMenu('Thailand Post Tracker')
.addItem('Renew AccessToken', 'getNewAccessToken')
.addToUi();
};
const getNewAccessToken = () => {
const activeSheet = SpreadsheetApp.getActiveSpreadsheet();
//อ้างอิงถึง cell Static Token และ Access Token ใน Sheet
const staticTokenCell = activeSheet.getRangeByName('StaticToken');
const accessTokenCell = activeSheet.getRangeByName('AccessToken');
//ดึงเอา static token ออกมาจาก cell
const staticToken = staticTokenCell.getValue();
//ทำการ request ขอ getToken จาก API
const accessToken = ThailandPost.getToken(staticToken);
//บันทึก accessToken ที่ได้ลงบน cell เพื่อใช้ต่อในอนาคต (ก็มันใช้ได้ตั้งเดือนนึง)
accessTokenCell.setValue(accessToken);
};
//อย่าลืมประกาศเป็น global ด้วย
global.onOpen = onOpen;
global.getNewAccessToken = getNewAccessToken;
เรียบร้อยแล้วก็ save หลังจากนั้นก็
npm run deploy
ลอง Refresh หน้า Sheet แล้วจะมีเมนูใหม่ชื่อ “Thailand Post Tracker” โผล่ขึ้นมา ลองคลิก “Renew AccessToken” เราจะเห็นว่ามี AccessToken ถูกเขียนลงไปในช่องว่าง

สร้าง Formula สำหรับ GetItems #
ในที่สุดก็มาถึงส่วนที่เรารอคอยที่ไฟล์ /src/service/index.js
ผมเพิ่ม getItems()
เข้ามาโดย payload
ผมจะตั้งตายตัวเป็นภาษาไทยและดึงเอาข้อมูลมาทั้งหมดครับ
src/service/index.js
getItems(accessToken, barcode) {
const options = {
//กำหนดข้อมูลตาม API Documentations
method: 'POST',
contentType: 'application/json',
headers: {
Authorization: `Token ${accessToken}`,
'Content-Type': 'application/json'
},
validateHttpsCertificates: false,
//payload คือ body ตาม document นะครับ
//อย่าลืมเปลี่ยนเป็น json string ด้วยล่ะ
payload: JSON.stringify({
status: 'all',
language: 'TH',
barcode: [barcode]
})
};
const data = UrlFetchApp.fetch(`${url}/track`, options);
const { response } = JSON.parse(data);
//return กลับไปเฉพาะ items เพราะเราอยากได้แค่สถานะ
return response.items[barcode];
}
เสร็จแล้วเราก็มาเขียน Formula สำหรับ Sheet ที่ src/index.js
ครับ ผมก็เพิ่ม ThailandPostTrack()
คำสั่งนี้จะรับเอา barcode
และ type
ในการแสดงข้อมูลดังนี้ครับ
- recent แสดงข้อมูลพัสดุล่าสุด
- first แสดงข้อมูลชุดแรกของพัสดุ
- all แสดงข้อมูลทั้งหมดตั้งแต่เริ่มส่งจนถึงปลายทาง
const ThailandPostTrack = (barcode, type) => {
//อ้างอิงถึง spreadsheet และ accessToken ที่เก็บไว้
const activeSheet = SpreadsheetApp.getActiveSpreadsheet();
const accessToken = activeSheet.getRangeByName('AccessToken').getValue();
//getItems ด้วย accessToken และ barcode ที่ได้มาจาก input parameter
const items = ThailandPost.getItems(accessToken, barcode);
//เปลี่ยน items ให้เหลือแค่ค่าที่เราอย่างได้ ผมอยากได้แค่ สถานะ, วันเวลา และสถานที่
//ที่ใส่ Array เพราะผมต้องการแสดงผลหลาย cells
const results = items.map(item => [item.status_description, item.status_date, item.location]);
if (results.length === 0) {
return 'ไม่พบข้อมูล';
}
//กำหนดการ return จากรูปแบบการแสดงผล
//ผมใช่้ Array ครอบตลอดเพราะต้องการให้แสดงผลแนวนอนไม่ใช่แนวตั้ง
switch (type) {
case 'recent':
return [results[results.length - 1]];
case 'first':
return [results[0]];
case 'all':
return results;
default:
return [results[results.length - 1]];
}
};
//เหมือนเดิมเลย อย่าลิมประกาศเป็น global ด้วยนะครับ
global.ThailandPostTrack = ThailandPostTrack;
จากนั้นก็ save แล้ว
npm run deploy
เรียกสูตร =ThailandPostTrack() จริงๆบ้าง #
ถ้า sheet Token
มีข้อมูลครบอยู่แล้ว เราก็จะได้ accessToken มาใช้เรียก GetItems
ได้แล้ว
=ThailandPostTrack("หมายเลขพัสดุ", "รูปแบบการแสดงผล")
//type: recent, first, all

Source Code #
เรียบร้อยแล้วครับ หวังว่าบทความนี้จะทำให้หลายๆคนเห็นภาพการเขียน Google Apps Script เพื่อใช้ call API แล้วจัดการ response ที่ได้มาเพื่อเอามาแสดงบน sheet ของเราเอง จริงๆส่วนนี้เราสามารถต่อยอดเป็นการทำ Library หรือทำเป็น Add-On ก็ได้นะครับ แต่เพื่อไม่ให้ยาวเกินไปผมจะขอยกไปเขียนในบทความต่อๆไปแทนนะครับ เหมือนเดิมครับท่านใดมีคำถามสามารถสอบถามเข้ามาที่ Inbox ของ Facebook Page ได้เลยนะครับ